//
// Example DDE client for Hondata application
//
// Copyright (c) 2013, Hondata Inc
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Hondata nor the names of its contributors may be 
//       used to endorse or promote products derived from this software without 
//       specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL HONDATA BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//

//
// Compiled under Dev-C++ 5.4.1 http://orwelldevcpp.blogspot.com/
//

#include <windows.h>
#include <ddeml.h>
#include "resource.h"

// Functions
LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Log(const char * msg);
void DDE_Connect(void);
void DDE_Disconnect(void);
HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv,
         HSZ hsz1, HSZ hsz2, HDDEDATA hData,
         ULONG_PTR dwData1, ULONG_PTR dwData2);
         
// Constants         
const char * szApp = "SManager";
const char * szTopic = "Sensors";

// DDE globals
DWORD DDEInstance = 0;
HCONV hConv = 0;
HSZ hszApp = 0;
HSZ hszTopic = 0;
HSZ hszItem = 0;

//
// Create a modal dialog as our main window
//
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) 
{
	if(DdeInitialize(&DDEInstance, (PFNCALLBACK)&DdeCallback, APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0) == DMLERR_NO_ERROR)
	{
		hszApp = DdeCreateStringHandle(DDEInstance, szApp, 0);
		
		DialogBox(hInstance, MAKEINTRESOURCE(DIALOG_MAIN), NULL, (DLGPROC)DialogProc);
		
		DdeFreeStringHandle(DDEInstance, hszApp);
		DdeUninitialize(DDEInstance);
	}
	return 0;
}

//
// Handle messages from our main window dialog
//
LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch(uMsg)
	{
		case WM_INITDIALOG:
			{
			 	// Centre window
      	RECT rc;
        GetWindowRect(hWnd, &rc);
        int nWidth = rc.right - rc.left;
        int nHeight = rc.bottom - rc.top;
        int X = ((int)GetSystemMetrics(SM_CXFULLSCREEN) - nWidth) / 2;
        int Y = ((int)GetSystemMetrics(SM_CYFULLSCREEN) - nHeight) / 2;
        MoveWindow(hWnd, X, Y, nWidth, nHeight, true);
        
        // Default to the Rpm sensor
        SetDlgItemText(hWnd, IDC_SENSOR, "Rpm");
        
        Log("Ready");
			}
			return true;
			
		case WM_COMMAND:
			switch(LOWORD(wParam))
			{
				case IDC_START:
					{
						Log("Start");
						DDE_Connect();
						
						// Send request for the item name in sensor edit control
						char szSensor[128];
						GetDlgItemText(hWnd, IDC_SENSOR, szSensor, sizeof(szSensor)-1);
						hszItem = DdeCreateStringHandle(DDEInstance, szSensor, 0);
						if(hszItem != NULL)
						{
							HDDEDATA hData = DdeClientTransaction(NULL, 0, hConv, hszItem, CF_TEXT, XTYP_ADVSTART, 1000, NULL);
							if(hData == NULL)
								Log("DdeClientTransaction failed");
							DdeFreeStringHandle(DDEInstance, hszItem);
						}
					}
					break;
					
				case IDC_STOP:
					// Stop requests
					// Could also use DdeClientTransaction with XTYP_ADVSTOP
					Log("Stop");
					DDE_Disconnect();
					break;					
			}
			return true;
			
		case WM_CLOSE:
			DDE_Disconnect();
			EndDialog(hWnd, false);
			return true;
	}
	return false;
}

//
// Simple log to output window
//
void Log(const char * msg)
{
	HWND hWndDialog = FindWindow(NULL, WINDOW_CAPTION);
	HWND hWndLog = GetDlgItem(hWndDialog, IDC_OUTPUT);
	SendMessage(hWndLog, EM_SETSEL, -1, -1);
	SendMessage(hWndLog, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)msg);
	SendMessage(hWndLog, EM_SETSEL, -1, -1);
	SendMessage(hWndLog, EM_REPLACESEL, FALSE, (LPARAM)(LPCTSTR)"\r\n");
}

//
// Connect to DDE server
//
void DDE_Connect(void)
{
	DDE_Disconnect();
 	hszTopic = DdeCreateStringHandle(DDEInstance, szTopic, 0);
 	hConv = DdeConnect(DDEInstance, hszApp, hszTopic, NULL);
}

//
// Disconnect from DDE server
//
void DDE_Disconnect(void)
{
	if(hszTopic)
	{
		DdeFreeStringHandle(DDEInstance, hszTopic);
		hszTopic = 0;
	}
	if(hConv)
	{
		DdeDisconnect(hConv);
		hConv = 0;
	}
}

//
// Handle DDE callback requests
//
HDDEDATA CALLBACK DdeCallback(UINT uType, UINT uFmt, HCONV hconv,
         HSZ hsz1, HSZ hsz2, HDDEDATA hData,
         ULONG_PTR dwData1, ULONG_PTR dwData2)
{
	switch(uType)
	{
		case XTYP_ADVDATA:
			// We have data
			{
				Log("XTYP_ADVDATA");
				DWORD DataLen = 0;
				char * pData = (char *)DdeAccessData(hData, &DataLen);
				if(pData != NULL)
				{
					pData[DataLen] = '\x0';
					Log(pData);
					HWND hWndDialog = FindWindow(NULL, WINDOW_CAPTION);
					SetDlgItemText(hWndDialog, IDC_VALUE, pData);			
				}
			}
			break;
			 		
		case XTYP_DISCONNECT:
			// DDE server has disappeared
			Log("XTYP_DISCONNECT");
			DDE_Disconnect();
			break;
			
	}
	return 0;
}


